package com.xbx.zuul.auth.config;

import com.xbx.common.utils.ObjectUtils;
import com.xbx.zuul.cache.FilterCache;
import com.xbx.zuul.dataobject.UserDOAndRoleDO;
import com.xbx.zuul.mapper.UserRoleDOMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilter;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

import javax.servlet.Filter;
import java.util.*;

/**
 * 清除shiro缓存bean
 *
 * @author 89005691
 * @create 2018-09-11 16:06
 */
@Repository
@Slf4j
public class ShiroCleanBean {

    @Autowired
    private ShiroFilterFactoryBean shiroFilterFactoryBean;

    @Autowired
    private UserRoleDOMapper userRoleDOMapper;

    @Value("${safetyUrl}")
    private String safetyUrl="";

    @Autowired
    private FilterCache filterCache;

    /**
     * 重新加载权限
     */
    public void updatePermission(String updateType) {

        synchronized (shiroFilterFactoryBean) {

            AbstractShiroFilter shiroFilter = null;
            try {
                shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
            } catch (Exception e) {
                log.error("updatePermission更新权限错误!");
                return;
            }

            // 一致则返回
            boolean isDiff = filterCache.diffFilterVersion(updateType);
            if (isDiff) {

                return;
            }

            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
            DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();

            // 清空老的权限控制
            manager.getFilterChains().clear();

            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();

            loadShiroFilterChain(shiroFilterFactoryBean);
            Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();

            for (Map.Entry<String, String> entry : chains.entrySet()) {

                String url = entry.getKey();
                String chainDefinition = entry.getValue().trim().replace(" ", "");
                manager.createChain(url, chainDefinition);
            }
        }
    }

    /**
     * 加载shiroFilter权限控制规则（从数据库读取然后配置）,角色/权限信息由MyShiroCasRealm对象提供doGetAuthorizationInfo实现获取来的
     */
    private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean){

        Map<String, Filter> filters = new HashMap<>();
        shiroFilterFactoryBean.setFilters(filters);
        /////////////////////// 下面这些规则配置最好配置到配置文件中 ///////////////////////
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        // authc：该过滤器下的页面必须登录后才能访问，它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter
        // anon: 可以理解为不拦截
        // user: 登录了就不拦截
        // roles["admin"] 用户拥有admin角色
        // perms["permission1"] 用户拥有permission1权限
        // filter顺序按照定义顺序匹配，匹配到就验证，验证完毕结束。
        // url匹配通配符支持：? * **,分别表示匹配1个，匹配0-n个（不含子路径），匹配下级所有路径

        //1.shiro集成cas后，首先添加该规则
        filterChainDefinitionMap.put(ShiroConfiguration.CAS_FILTER_URL_PATTERN, "casFilter");
        //filterChainDefinitionMap.put("/logout","logout"); //logut请求采用logout filter

        //2.不拦截的请求
        if(StringUtils.isNotEmpty(this.safetyUrl)){

            // 安全的请求url
            List<String> urls = Arrays.asList(this.safetyUrl.split(","));
            for(String url : urls){

                filterChainDefinitionMap.put(url, DefaultFilter.anon.name());
            }
        }
        // 默认配置
        filterChainDefinitionMap.put("/swagger-ui.html","anon");
        filterChainDefinitionMap.put("/swagger/**","anon");
        filterChainDefinitionMap.put("/webjars/**", "anon");
        filterChainDefinitionMap.put("/swagger-resources/**","anon");
        filterChainDefinitionMap.put("/v2/**","anon");


        //3.拦截的请求（从本地数据库获取或者从casserver获取(webservice,http等远程方式)，看你的角色权限配置在哪里）
        List<UserDOAndRoleDO> userDOAndRoleDOS = userRoleDOMapper.selectAllRoleInfos();

        // 加载角色权限
        if(ObjectUtils.isNotNull(userDOAndRoleDOS)){

            this.loadUserRolePermission(userDOAndRoleDOS, filterChainDefinitionMap);
        }

        log.info("更新权限过滤器，当前过滤器详情为{}", filterChainDefinitionMap.toString());

        //  所有请求都需要拦截
        filterChainDefinitionMap.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    }

    /**
     * 加载角色权限
     */
    private void loadUserRolePermission(List<UserDOAndRoleDO> userDOAndRoleDOS, Map<String, String> filterChainDefinitionMap) {

        for (UserDOAndRoleDO userDOAndRoleDO : userDOAndRoleDOS) {

            if (StringUtils.isEmpty(userDOAndRoleDO.getRoleCode())) {

                // 使用内置角色保护url
                filterChainDefinitionMap.put(userDOAndRoleDO.getActionUrl(), "anyofroles[\"" + ShiroConfiguration.SYSTEM_ROLE + "\"]");
            } else {

                filterChainDefinitionMap.put(userDOAndRoleDO.getActionUrl(), "anyofroles[\"" + userDOAndRoleDO.getRoleCode() + "\"]");
            }
        }
    }
}
